<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- 
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License. 
-->
<html>
<head>
    <link type="text/css" rel="stylesheet" href="https://struts.apache.org/css/default.css">
    <style type="text/css">
        .dp-highlighter {
            width:95% !important;
        }
    </style>
    <style type="text/css">
        .footer {
            background-image:      url('https://cwiki.apache.org/confluence/images/border/border_bottom.gif');
            background-repeat:     repeat-x;
            background-position:   left top;
            padding-top:           4px;
            color:                 #666;
        }
    </style>
    <link href='https://struts.apache.org/highlighter/style/shCoreStruts.css' rel='stylesheet' type='text/css' />
    <link href='https://struts.apache.org/highlighter/style/shThemeStruts.css' rel='stylesheet' type='text/css' />
    <script src='https://struts.apache.org/highlighter/js/shCore.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushPlain.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushXml.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushJava.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushJScript.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushGroovy.js' type='text/javascript'></script>
    <script src='https://struts.apache.org/highlighter/js/shBrushBash.js' type='text/javascript'></script>
    <script type="text/javascript">
        SyntaxHighlighter.defaults['toolbar'] = false;
        SyntaxHighlighter.all();
    </script>
    <script type="text/javascript" language="javascript">
        var hide = null;
        var show = null;
        var children = null;

        function init() {
            /* Search form initialization */
            var form = document.forms['search'];
            if (form != null) {
                form.elements['domains'].value = location.hostname;
                form.elements['sitesearch'].value = location.hostname;
            }

            /* Children initialization */
            hide = document.getElementById('hide');
            show = document.getElementById('show');
            children = document.all != null ?
                    document.all['children'] :
                    document.getElementById('children');
            if (children != null) {
                children.style.display = 'none';
                show.style.display = 'inline';
                hide.style.display = 'none';
            }
        }

        function showChildren() {
            children.style.display = 'block';
            show.style.display = 'none';
            hide.style.display = 'inline';
        }

        function hideChildren() {
            children.style.display = 'none';
            show.style.display = 'inline';
            hide.style.display = 'none';
        }
    </script>
    <title>JSON Plugin</title>
</head>
<body onload="init()">
<table border="0" cellpadding="2" cellspacing="0" width="100%">
    <tr class="topBar">
        <td align="left" valign="middle" class="topBarDiv" align="left" nowrap>
            &nbsp;<a href="home.html">Home</a>&nbsp;&gt;&nbsp;<a href="guides.html">Guides</a>&nbsp;&gt;&nbsp;<a href="plugin-developers-guide.html">Plugin Developers Guide</a>&nbsp;&gt;&nbsp;<a href="json-plugin.html">JSON Plugin</a>
        </td>
        <td align="right" valign="middle" nowrap>
            <form name="search" action="https://www.google.com/search" method="get">
                <input type="hidden" name="ie" value="UTF-8" />
                <input type="hidden" name="oe" value="UTF-8" />
                <input type="hidden" name="domains" value="" />
                <input type="hidden" name="sitesearch" value="" />
                <input type="text" name="q" maxlength="255" value="" />
                <input type="submit" name="btnG" value="Google Search" />
            </form>
        </td>
    </tr>
</table>

<div id="PageContent">
    <div class="pageheader" style="padding: 6px 0px 0px 0px;">
        <!-- We'll enable this once we figure out how to access (and save) the logo resource -->
        <!--img src="/wiki/images/confluence_logo.gif" style="float: left; margin: 4px 4px 4px 10px;" border="0"-->
        <div style="margin: 0px 10px 0px 10px" class="smalltext">Apache Struts 2 Documentation</div>
        <div style="margin: 0px 10px 8px 10px"  class="pagetitle">JSON Plugin</div>

        <div class="greynavbar" align="right" style="padding: 2px 10px; margin: 0px;">
            <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=2850922">
                <img src="https://cwiki.apache.org/confluence/images/icons/notep_16.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Edit Page"></a>
            <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=2850922">Edit Page</a>
            &nbsp;
            <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">
                <img src="https://cwiki.apache.org/confluence/images/icons/browse_space.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Browse Space"></a>
            <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">Browse Space</a>
            &nbsp;
            <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=2850922">
                <img src="https://cwiki.apache.org/confluence/images/icons/add_page_16.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Add Page"></a>
            <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=2850922">Add Page</a>
            &nbsp;
            <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=2850922">
                <img src="https://cwiki.apache.org/confluence/images/icons/add_blogentry_16.gif"
                     height="16" width="16" border="0" align="absmiddle" title="Add News"></a>
            <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=2850922">Add News</a>
        </div>
    </div>

    <div class="pagecontent">
        <div class="wiki-content">
            <div id="ConfluenceContent"><p>The JSON pluginprovides a "json" result type that serializes actions into JSON. The serialization process is recursive, meaning that the whole object graph, starting on the action class (base class not included) will be serialized (root object can be customized using the "root" attribute). If the interceptor is used, the action will be populated from the JSON content in the request, these are the rules of the interceptor:</p><ol><li>The "content-type" must be "application/json"</li><li>The JSON content must be well formed, see <a shape="rect" class="external-link" href="http://www.json.org" rel="nofollow">json.org</a> for grammar.</li><li>Action must have a public "setter" method for fields that must be populated.</li><li>Supported types for population are: Primitives (int,long...String), Date, List, Map, Primitive Arrays, Other class (more on this later), and Array of Other class.</li><li>Any object in JSON, that is to be populated inside a list, or a map, will be of type Map (mapping from properties to values), any whole number will be of type Long, any decimal number will be of type Double, and any array of type List.</li></ol><p>Given this JSON string:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">{
   "doubleValue": 10.10,
   "nestedBean": {
      "name": "Mr Bean"
   },
   "list": ["A", 10, 20.20, {
      "firstName": "El Zorro"
   }],
   "array": [10, 20] 
}
</pre>
</div></div><p>The action must have a "setDoubleValue" method, taking either a "float" or a "double" argument (the interceptor will convert the value to the right one). There must be a "setNestedBean" whose argument type can be any class, that has a "setName" method taking as argument an "String". There must be a "setList" method that takes a "List" as argument, that list will contain: "A" (String), 10 (Long), 20.20 (Double), Map ("firstName" -&gt; "El Zorro"). The "setArray" method can take as parameter either a "List", or any numeric array.</p><div class="confluence-information-macro confluence-information-macro-tip"><span class="aui-icon aui-icon-small aui-iconfont-approve confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>So serialize your objects to JSON in javascript see <a shape="rect" class="external-link" href="http://json.org/json2.js" rel="nofollow">json2</a>.</p></div></div><div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p><code>root</code> attribute must be set on the JSONInterceptor when dealing with JSON array.</p></div></div><h2 id="JSONPlugin-Installation">Installation</h2><p>This plugin can be installed by copying the plugin jar into your application's <code>/WEB-INF/lib</code> directory. No other files need to be copied or created.</p><p>To use maven, add this to your pom:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;dependencies&gt;
   ...
   &lt;dependency&gt;
       &lt;groupId&gt;org.apache.struts&lt;/groupId&gt;
       &lt;artifactId&gt;struts2-json-plugin&lt;/artifactId&gt;
       &lt;version&gt;STRUTS_VERSION&lt;/version&gt;
   &lt;/dependency&gt;
   ...
&lt;/dependencies&gt;
</pre>
</div></div><h2 id="JSONPlugin-CustomizingSerializationandDeserialization">Customizing Serialization and Deserialization</h2><p>Use the JSON annotation to customize the serialization/deserialization process. Available JSON annotation fields:</p><div class="table-wrap"><table class="confluenceTable"><tbody><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Name</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Description</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Default Value</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Serialization</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Deserialization</p></th></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>name</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Customize field name</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>empty</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>yes</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>no</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>serialize</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Include in serialization</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>true</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>yes</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>no</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>deserialize</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Include in deserialization</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>true</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>no</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>yes</p></td></tr><tr><td colspan="1" rowspan="1" class="confluenceTd"><p>format</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Format used to format/parse a Date field</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>"yyyy-MM-dd'T'HH:mm:ss"</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>yes</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>yes</p></td></tr></tbody></table></div><h3 id="JSONPlugin-Excludingproperties">Excluding properties</h3><p>A comma-delimited list of regular expressions can be passed to the JSON Result and Interceptor, properties matching any of these regular expressions will be ignored on the serialization process:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;!-- Result fragment --&gt;
&lt;result type="json"&gt;
  &lt;param name="excludeProperties"&gt;
    login.password,
    studentList.*\.sin
  &lt;/param&gt;
&lt;/result&gt;

&lt;!-- Interceptor fragment --&gt;
&lt;interceptor-ref name="json"&gt;
  &lt;param name="enableSMD"&gt;true&lt;/param&gt;
  &lt;param name="excludeProperties"&gt;
    login.password,
    studentList.*\.sin
  &lt;/param&gt;
&lt;/interceptor-ref&gt;
</pre>
</div></div><h3 id="JSONPlugin-Includingproperties">Including properties</h3><p>A comma-delimited list of regular expressions can be passed to the JSON Result to restrict which properties will be serialized. ONLY properties matching any of these regular expressions will be included in the serialized output.</p><div class="confluence-information-macro confluence-information-macro-note"><p class="title">Note</p><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Exclude property expressions take precedence over include property expressions. That is, if you use include and exclude property expressions on the same result, include property expressions will not be applied if an exclude exclude property expression matches a property first.</p></div></div><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;!-- Result fragment --&gt;
&lt;result type="json"&gt;
  &lt;param name="includeProperties"&gt;
    ^entries\[\d+\]\.clientNumber,
    ^entries\[\d+\]\.scheduleNumber,
    ^entries\[\d+\]\.createUserId
  &lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><h3 id="JSONPlugin-RootObject">Root Object</h3><p>Use the "root" attribute(OGNL expression) to specify the root object to be serialized.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="root"&gt;
    person.job
  &lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><p>The "root" attribute(OGNL expression) can also be used on the interceptor to specify the object that must be populated, <strong>make sure this object is not null</strong>.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;interceptor-ref name="json"&gt;
  &lt;param name="root"&gt;bean1.bean2&lt;/param&gt;
&lt;/interceptor-ref&gt;
</pre>
</div></div><h3 id="JSONPlugin-Wrapping">Wrapping</h3><p>For several reasons you might want to wrap the JSON output with some text, like wrapping with comments, adding a prefix, or to use file uploads which require the result to be wrapped in a textarea. Use <em>wrapPrefix</em> to add content in the beginning and <em>wrapPostfix</em> to add content at the end. This settings take precedence over "wrapWithComments" and "prefix" which are deprecated from 0.34 on. Examples:<br clear="none"> Wrap with comments:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="wrapPrefix"&gt;/*&lt;/param&gt;
  &lt;param name="wrapSuffix"&gt;*/&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><p>Add a prefix:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="wrapPrefix"&gt;{}&amp;&amp;&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><p>Wrap for file upload:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="wrapPrefix"&gt;&lt;![CDATA[&lt;html&gt;&lt;body&gt;&lt;textarea&gt;]]&gt;&lt;/param&gt;
  &lt;param name="wrapSuffix"&gt;&lt;![CDATA[&lt;/textarea&gt;&lt;/body&gt;&lt;/html&gt;]]&gt;&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><h3 id="JSONPlugin-WrapwithComments">Wrap with Comments</h3><div class="confluence-information-macro confluence-information-macro-warning"><span class="aui-icon aui-icon-small aui-iconfont-error confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p><em>wrapWithComments</em> is deprecated from 0.34, use <em>wrapPrefix</em> and <em>wrapSuffix</em> instead.</p></div></div><div class="confluence-information-macro confluence-information-macro-warning"><span class="aui-icon aui-icon-small aui-iconfont-error confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p><em>wrapWithComments</em> can turn safe JSON text into dangerous text. For example,</p><p><a shape="rect" class="createlink" href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&amp;title=%22*%2F+alert%28%27XSS%27%29%3B+%2F*%22&amp;linkCreation=true&amp;fromPageId=2850922">"*/ alert('XSS'); /*"</a></p><p>Thanks to Douglas Crockford for the tip!. Consider using <strong>prefix</strong> instead.</p></div></div><p>If the serialized JSON is <em>{name: 'El Zorro'}</em>. Then the output will be: <em>{}&amp;&amp; ({name: 'El Zorro'}</em></p><p>If the "wrapWithComments" (false by default) attribute is set to true, the generated JSON is wrapped with comments like:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">/* {
   "doubleVal": 10.10,
   "nestedBean": {
      "name": "Mr Bean"
   },
   "list": ["A", 10, 20.20, {
      "firstName": "El Zorro"
   }],
   "array": [10, 20] 
} */
</pre>
</div></div><p>To strip those comments use:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">var responseObject = eval("("+data.substring(data.indexOf("\/\*")+2, data.lastIndexOf("\*\/"))+")");
</pre>
</div></div><h3 id="JSONPlugin-Prefix">Prefix</h3><div class="confluence-information-macro confluence-information-macro-warning"><span class="aui-icon aui-icon-small aui-iconfont-error confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p><em>prefix</em> is deprecated from 0.34, use <em>wrapPrefix</em> and <em>wrapSuffix</em> instead.</p></div></div><p>If the parameter <em>prefix</em> is set to true, the generated JSON will be prefixed with "{}&amp;&amp; ". This will help prevent hijacking. See <a shape="rect" class="external-link" href="http://trac.dojotoolkit.org/ticket/6380" rel="nofollow">this Dojo Ticket</a> for details:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="prefix"&gt;true&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><h3 id="JSONPlugin-BaseClasses">Base Classes</h3><p>By default properties defined on base classes of the "root" object won't be serialized, to serialize properties in all base classes (up to Object) set "ignoreHierarchy" to false in the JSON result:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="ignoreHierarchy"&gt;false&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><h3 id="JSONPlugin-Enumerations">Enumerations</h3><p>By default, an Enum is serialized as a name=value pair where value = name().</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">  public enum AnEnum {
     ValueA,
     ValueB
  }

  JSON:  "myEnum":"ValueA"
</pre>
</div></div><p>Use the "enumAsBean" result parameter to serialize Enum's as a bean with a special property _name with value name(). All properties of the enum are also serialized.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">  public enum AnEnum {
     ValueA("A"),
     ValueB("B");

     private String val;
     
     public AnEnum(val) {
        this.val = val;
     }
     public getVal() {
        return val;
     }
   }

  JSON:  myEnum: { "_name": "ValueA", "val": "A" }
</pre>
</div></div><p>Enable this parameter through struts.xml:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="enumAsBean"&gt;true&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><h3 id="JSONPlugin-Compressingtheoutput.">Compressing the output.</h3><p>Set the <em>enableGZIP</em> attribute to true to gzip the generated json response. The request <strong>must</strong> include "gzip" in the "Accept-Encoding" header for this to work.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="enableGZIP"&gt;true&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><h3 id="JSONPlugin-Preventingthebrowserfromcachingtheresponse">Preventing the browser from caching the response</h3><p>Set <em>noCache</em> to true(false by default) to set the following headers in the response:</p><ul><li>Cache-Control: no-cache</li><li>Expires: 0</li><li>Pragma: No-cache</li></ul><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="noCache"&gt;true&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><h3 id="JSONPlugin-Excludingpropertieswithnullvalues">Excluding properties with null values</h3><p>By default fields with null values are serialized like {property_name: null}. This can be prevented by setting <em>excludeNullProperties</em> to true.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="excludeNullProperties"&gt;true&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><h3 id="JSONPlugin-StatusandErrorcode">Status and Error code</h3><p>Use <em>statusCode</em> to set the status of the response:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="statusCode"&gt;304&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><p>And <em>errorCode</em> to send an error(the server might end up sending something to the client which is not the serialized JSON):</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="errorCode"&gt;404&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><h3 id="JSONPlugin-JSONP">JSONP</h3><p>To enable JSONP, set the parameter <em>callbackParameter</em> in either the JSON Result or the Interceptor. A parameter with that name will be read from the request, and it value will be used as the JSONP function. Assuming that a request is made with the parameter "callback"="exec":</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="callbackParameter"&gt;callback&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><p>And that the serialized JSON is <em>{name: 'El Zorro'}</em>. Then the output will be: <em>exec({name: 'El Zorro'})</em></p><h3 id="JSONPlugin-ContentType">Content Type</h3><p>Content type will be set to <em>application/json-rpc</em> by default if SMD is being used, or <em>application/json</em> otherwise. Sometimes it is necessary to set the content type to something else, like when uploading files with Dojo and YUI. Use the <em>contentType</em> parameter in those cases.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="contentType"&gt;text/html&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><h3 id="JSONPlugin-Encoding">Encoding</h3><p>User can define encoding per result or base on default assigned to struts.i18n.encoding. To define encoding for given result add encoding param as below:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;result type="json"&gt;
  &lt;param name="encoding"&gt;UTF-8&lt;/param&gt;
&lt;/result&gt;
</pre>
</div></div><h2 id="JSONPlugin-Example">Example</h2><h3 id="JSONPlugin-SetupAction">Setup Action</h3><p>This simple action has some fields:</p><p>Example:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">import java.util.HashMap;
import java.util.Map;

import com.opensymphony.xwork2.Action;

public class JSONExample {
    private String field1 = "str";
    private int[] ints = {10, 20};
    private Map map = new HashMap();
    private String customName = "custom";

    //'transient' fields are not serialized
    private transient String field2;

    //fields without getter method are not serialized
    private String field3;

    public String execute() {
        map.put("John", "Galt");
        return Action.SUCCESS;
    }

    public String getField1() {
        return field1;
    }

    public void setField1(String field1) {
        this.field1 = field1;
    }

    public int[] getInts() {
        return ints;
    }

    public void setInts(int[] ints) {
        this.ints = ints;
    }

    public Map getMap() {
        return map;
    }

    public void setMap(Map map) {
        this.map = map;
    }

    @JSON(name="newName")
    public String getCustomName() {
        return this.customName;
    }
}
</pre>
</div></div><h3 id="JSONPlugin-Writethemappingfortheaction">Write the mapping for the action</h3><ol><li>Add the map inside a package that extends "json-default"</li><li>Add a result of type "json"</li></ol><p>Example with Convention Plugin Configuration:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">import java.util.HashMap;
import java.util.Map;

import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.convention.annotation.Result;

@Result(type = "json")
public class JSONExample extends ActionSupport {
// action code
}
</pre>
</div></div><p>Example with XML Configuration:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd"&gt;

&lt;struts&gt;

  &lt;package name="example"  extends="json-default"&gt;
     &lt;action name="JSONExample" class="example.JSONExample"&gt;
        &lt;result type="json"/&gt;
     &lt;/action&gt;
  &lt;/package&gt;

&lt;/struts&gt;
</pre>
</div></div><h4 id="JSONPlugin-JSONexampleoutput">JSON example output</h4><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">{  
   "field1" : "str", 
   "ints": [10, 20],
   "map": {
       "John":"Galt"
   },
   "newName": "custom"
}
</pre>
</div></div><h4 id="JSONPlugin-AcceptingJSON">Accepting JSON</h4><p>Your actions can accept incoming JSON if they are in package which uses&#160;<code>json</code> interceptor or by adding reference to it as follow:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">@InterceptorRef(value="json")</pre>
</div></div><h2 id="JSONPlugin-JSONRPC">JSON RPC</h2><p>The json plugin can be used to execute action methods from javascript and return the output. This feature was developed with Dojo in mind, so it uses <a shape="rect" class="external-link" href="http://manual.dojotoolkit.org/WikiHome/DojoDotBook/Book9" rel="nofollow">Simple Method Definition</a> to advertise the remote service. Let's work it out with an example(useless as most examples).</p><p>First write the action:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">package smd;

import com.googlecode.jsonplugin.annotations.SMDMethod;
import com.opensymphony.xwork2.Action;

public class SMDAction {
    public String smd() {
        return Action.SUCCESS;
    }
    
    @SMDMethod
    public Bean doSomething(Bean bean, int quantity) {
        bean.setPrice(quantity * 10);
        return bean;
    }
}
</pre>
</div></div><p>Methods that will be called remotely <strong>must</strong> be annotated with the <em>SMDMethod</em> annotation, for security reasons. The method will take a bean object, modify its price and return it. The action can be annotated with the <em>SMD</em> annotation to customize the generated SMD (more on that soon), and parameters can be annotated with <em>SMDMethodParameter</em>. As you can see, we have a "dummy", <em>smd</em> method. This method will be used to generate the Simple Method Definition (a definition of all the services provided by this class), using the "json" result.</p><p>The bean class:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">package smd;

public class Bean {
    private String type;
    private int price;
    
    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

}
</pre>
</div></div><p>The mapping:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;">&lt;package name="RPC" namespace="/nodecorate" extends="json-default"&gt;
    &lt;action name="SMDAction" class="smd.SMDAction" method="smd"&gt;
        &lt;interceptor-ref name="json"&gt;
            &lt;param name="enableSMD"&gt;true&lt;/param&gt;
        &lt;/interceptor-ref&gt;
        &lt;result type="json"&gt;
             &lt;param name="enableSMD"&gt;true&lt;/param&gt;
        &lt;/result&gt;
    &lt;/action&gt;
&lt;/package&gt;
</pre>
</div></div><p>Nothing special here, except that <strong>both</strong> the interceptor and the result must be applied to the action, and "enableSMD" must be enabled for both.</p><p>Now the javascript code:</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">&lt;s:url id="smdUrl" namespace="/nodecorate" action="SMDAction" /&gt;
&lt;script type="text/javascript"&gt;
    //load dojo RPC
    dojo.require("dojo.rpc.*");
    
    //create service object(proxy) using SMD (generated by the json result)
    var service = new dojo.rpc.JsonService("${smdUrl}");
    
    //function called when remote method returns
    var callback = function(bean) {
        alert("Price for " + bean.type + " is " + bean.price);
    };
    
    //parameter
    var bean = {type: "Mocca"};
    
    //execute remote method
    var defered = service.doSomething(bean, 5);

    //attach callback to defered object
    defered.addCallback(callback);
&lt;/script&gt;
</pre>
</div></div><p>Dojo's JsonService will make a request to the action to load the SMD, which will return a JSON object with the definition of the available remote methods, using that information Dojo creates a "proxy" for those methods. Because of the asynchronous nature of the request, when the method is executed, a deferred object is returned, to which a callback function can be attached. The callback function will receive as a parameter the object returned from your action. That's it.</p><h2 id="JSONPlugin-Proxiedobjects">Proxied objects</h2><p>As annotations are not inherited in Java, some user might experience problems while trying to serialize objects that are proxied. eg. when you have attached AOP interceptors to your action.</p><p>In this situation, the plugin will not detect the annotations on methods in your action.</p><p>To overcome this, set the "ignoreInterfaces" result parameter to false (true by default) to request that the plugin inspects all interfaces and superclasses of the action for annotations on the action's methods.</p><p>NOTE: This parameter should only be set to false if your action could be a proxy as there is a performance cost caused by recursion through the interfaces.</p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;">&lt;action name="contact" class="package.ContactAction" method="smd"&gt;
   &lt;interceptor-ref name="json"&gt;
      &lt;param name="enableSMD"&gt;true&lt;/param&gt;
      &lt;param name="ignoreSMDMethodInterfaces"&gt;false&lt;/param&gt;
   &lt;/interceptor-ref&gt;
   &lt;result type="json"&gt;
      &lt;param name="enableSMD"&gt;true&lt;/param&gt;
      &lt;param name="ignoreInterfaces"&gt;false&lt;/param&gt;
   &lt;/result&gt;
   &lt;interceptor-ref name="default"/&gt;
&lt;/action&gt;
</pre>
</div></div></div>
        </div>

        
    </div>
</div>
<div class="footer">
    Generated by CXF SiteExporter
</div>
</body>
</html>
